<template>
  <div v-loading="loading" class="news-publish">

    <div class="tip">
      <svg @click="goBack()" t="1743402074255" class="backIcon" viewBox="0 0 1024 1024" version="1.1"
        xmlns="http://www.w3.org/2000/svg" p-id="2913" width="20" height="20">
        <path
          d="M739.555556 198.599111L412.842667 525.312 739.555556 852.024889l-84.821334 84.764444-411.534222-411.477333L654.791111 113.777778z"
          fill="#fff" p-id="2914">
        </path>
      </svg>
      发布文章
    </div>

    <div class="titleBox">
      <el-input v-model="News_addDTO.title" style="width: 100%;" size="large" clearable placeholder="请输入标题" />
    </div>

    <div class="CategoriesAndCoverBox">
      <!--分类-->
      <div class="Categories-box">
        <el-select v-model="News_addDTO.categoryId" placeholder="请选择分类" clearable size="large" style="width: 100%;">
          <el-option v-for="item in newsStoreObject.newsCategoryInfo" :key="item.id" :label="item.name" :value="item.id" />
        </el-select>
        <el-button v-if="fileList.length != 0" @click="myClearFile()" style="width: 100%;height: 40px;" type="primary">重新选择封面</el-button>
      </div>
      <!--封面-->
      <div class="Cover-box">
        <el-upload  ref="CoverUpload" class="avatar-uploader" v-model:file-list="fileList"
        :action="path.baseUrl + '/common/upload'" :data="CoverUploadData" :headers="CoverUploadHeaders"
          :auto-upload="false" :limit="1" :on-exceed="handleExceed" :on-success="handleUpImage"
          :before-upload="beforeImageUpload" list-type="picture" accept="image/*">
          <template #file="{ file }">
            <el-image style="width: 46vw; height: 25vw; min-width: 155px; min-height: 85px;" 
              :src="file.url" :preview-src-list="[file.url]" :preview-teleported="true" fit="cover" />
          </template>
          <el-icon v-if="!fileList.length">
            <Plus />
          </el-icon>
        </el-upload>
      </div>
    </div>

    <div class="editBox">
      <Editor ref="RichTextEditorRef" v-model="News_addDTO.content"/>
    </div>

    <el-button @click="submitNews()" type="primary" class="submit-btn">立即发布</el-button>
  </div>
</template>


<script lang="ts" setup>
import { ref,onMounted,inject } from 'vue'
import api from '@/api';
import path from "@/api/path.js";
import Editor from '@/components/utils/RichTextEditor.vue'
import { genFileId } from 'element-plus'
import type { UploadInstance, UploadProps, UploadRawFile, UploadFile } from 'element-plus'
import { useRouter,onBeforeRouteLeave } from 'vue-router';
import { NewsStore } from '@/stores/newsInfoStore';
import { UserStore } from '@/stores/userInfoStore';
import { TipStore } from '@/stores/tipStore';


const disableCacheFor = inject('disableCacheFor') as (componentNameList: string[]) => void;
const router = useRouter();
const newsStoreObject = NewsStore();
const userStoreObject = UserStore();
const TipStoreObject = TipStore();


const News_addDTO = ref({
  id: null,
  title: null,
  frontCover: null,
  content: null,
  categoryId: null,
  authorId: null,
})
const RichTextEditorRef = ref() //富文本编辑器组件实例
const imgList1 = ref([])
const imgList2 = ref([])
const imgListObj = ref([])
const imgWhichHadDel = ref([])

const videoList1 = ref([])
const videoList2 = ref([])
const videoListObj = ref([])
const videoWhichHadDel = ref([])


//#region 封面上传
const CoverUpload = ref()
const CoverUploadHeaders = ref({ // 上传时附带的请求头  
  token: ''
})
const CoverUploadData = ref({ // 上传时附带的额外参数
  fullPath: 'img/client/',
})
const fileList = ref([]) // <--封面文件在这！！！

// 移除封面文件
const myClearFile = () => {
  CoverUpload.value!.clearFiles()
}

// 限制上传图片数量
const handleExceed: UploadProps['onExceed'] = (files) => {
  CoverUpload.value!.clearFiles()
  const file = files[0] as UploadRawFile
  file.uid = genFileId()
  CoverUpload.value!.handleStart(file)
}

// 上传前，限制的上传图片大小
const beforeImageUpload = (rawFile) => {
  if (rawFile.size / 1024 / 1024 > 2) {
    alert("单张图片大小不能超过2MB!");
    return false;
  }
  return true;
}
// 上传成功，获取返回的图片地址
const handleUpImage = (res) => {
  News_addDTO.value.frontCover = res.data;
}

//#endregion

//删除富文本编辑器中已经上传到服务器，但在编辑阶段就被删除的文件
const DeleteFileWhichHadUploadFromEditor = async() => {
  if(RichTextEditorRef.value){
      imgList1.value = RichTextEditorRef.value.imageList //拿到富文本编辑器中在编辑阶段上传的所有图片的完整路径
      imgListObj.value = RichTextEditorRef.value.getImgMethod() //拿到当前富文本编辑器中的图片对象
      imgList2.value = imgListObj.value.map(e => e.src); //拿到图片对象们的src属性
      imgWhichHadDel.value = imgList1.value.filter(item => !imgList2.value.includes(item)); //找出在编辑阶段就被删除的图片的完整路径

      videoList1.value = RichTextEditorRef.value.videoList
      videoListObj.value = RichTextEditorRef.value.getVideoMethod()
      videoList2.value = videoListObj.value.map(e => e.src); //拿到视频对象们的src属性
      videoWhichHadDel.value = videoList1.value.filter(item => !videoList2.value.includes(item)); //找出在编辑阶段就被删除的视频的完整路径

      //调用接口删除这些文件
      if(imgWhichHadDel.value.length != 0){
        console.log("要删除的图片对象为：",imgWhichHadDel.value)
        await api.deleteObject(imgWhichHadDel.value)
      }
      if(videoWhichHadDel.value.length != 0){
        console.log("要删除的视频对象为：",videoWhichHadDel.value)
        await api.deleteObject(videoWhichHadDel.value)
      }
  }
}

//从字符串中提取图片地址
const ExtractImgSrc = (htmlString) => {
    let regex = /<img[^>]*\/>/gi; //截取HTML字符串中的<img>标签的正则表达式
    let srcRegex = /src="([^"]*)"/i; //截取<img>标签中的src属性的正则表达式

    let imgTags = htmlString.match(regex); //所有匹配的<img>标签，因为一个文字里面可能有多张图片
    let srcValues = []; //所有src属性的值

    if (imgTags) {
        imgTags.forEach((tag) => {
            let match = tag.match(srcRegex); // 对每个<img>标签使用srcRegex正则表达式，过滤出src属性值
            if (match) {
                srcValues.push(match[1]); // 如果匹配成功，将src属性值添加到数组中
            }
        });
        return srcValues;
    } else {
        return []; //没有找到<img>标签
    }
}

//从字符串中提取视频地址
const ExtractVideoSrc = (htmlString) => {
    let regex = /<video[^>]*>([\s\S]*?)<\/video>/gi; //截取HTML字符串中的以<video开头，以</video>结尾的标签的正则表达式
    let srcRegex = /src="([^"]*)"/i; //截取<video>标签中的src属性的正则表达式

    let videoTags = htmlString.match(regex); //所有匹配的<video>标签，因为一个文章里面可能有多个视频
    let srcValues = []; //所有src属性的值

    if (videoTags) {
        videoTags.forEach((tag) => {
            let match = tag.match(srcRegex); // 对每个<img>标签使用srcRegex正则表达式，过滤出src属性值
            if (match) {
                srcValues.push(match[1]); // 如果匹配成功，将src属性值添加到数组中
            }
        });
        return srcValues;
    } else {
        return []; //没有找到<video>标签
    }
}

//把文章里面的图片或文件从服务器中删掉
const DeleteFile = async (contentList) => {

    let fullPathList_img = ExtractImgSrc(contentList); //提取出图片地址数组
    console.log("提取出的图片地址数组为：",fullPathList_img)
    let fullPathList_video = ExtractVideoSrc(contentList); //提取出视频地址数组
    console.log("提取出的视频地址数组为：",fullPathList_video)
    let fullPathList = fullPathList_img.concat(fullPathList_video); //合并数组
    
    console.log("（删除文件）准备发送的数据为：",fullPathList);
    await api.deleteObject(fullPathList).then(res => {
        console.log("（删除文件）后端返回的数据为：",res);
    }).catch(err => {
        console.log("错误原因为：",err)
    })

}


const loading = ref(false)
// 提交新闻
const submitNews = async() => {
  if(!News_addDTO.value.title || !News_addDTO.value.content || !News_addDTO.value.categoryId){
    alert("请填写完整信息")
    return
  }

  //加一个加载动画，结束上传后再去除，防止用户重复点击上传按钮
  loading.value = true;

  // 等待封面上传完毕后再执行下面的步骤
  if(fileList.value.length != 0){
    await new Promise((resolve, reject) => {
      // 调用 CoverUpload.value!.submit()
      CoverUpload.value!.submit();

      // 定义一个定时器，用于检查 News_addDTO.value.frontCover 是否有值
      const checkInterval = setInterval(() => {
        // 如果 News_addDTO.value.frontCover 有值，表示上传成功
        if (News_addDTO.value.frontCover) {
          clearInterval(checkInterval); // 清除定时器
          resolve(News_addDTO.value.frontCover); // resolve 表示上传成功
        }
      }, 100); // 每隔 100 毫秒检查一次

      // 设置一个超时时间，防止无限等待
      setTimeout(() => {
        clearInterval(checkInterval); // 清除定时器
        reject(new Error('图片上传超时')); // 超时后 reject
      }, 10000); // 超时时间为 10000 毫秒
    });
  }

  console.log("新增新闻准备发送的数据为：",News_addDTO.value);
  await api.addNews(News_addDTO.value).then(res => {
    if (res.data.code == 1) {
      TipStoreObject.successTip();
    } else {
      TipStoreObject.errorTip();
    }
  })

  await DeleteFileWhichHadUploadFromEditor() //在云存储中删除富文本编辑器中已经上传到服务器，但在编辑阶段就被删除的文件

  if(imgList2.value.length != 0){
    await api.deleteTempFile(imgList1.value) //删除本次存入临时文件标记表的信息（图片）
  }
  if(videoList2.value.length != 0){
    await api.deleteTempFile(videoList1.value) //删除本次存入临时文件标记表的信息（视频）
  }

  // 清空操作
  Object.keys(News_addDTO.value).forEach(key => {
    News_addDTO.value[key] = null;
  });
  loading.value = false;
  disableCacheFor(['Profile','Works']) //刷新组件的挂载，因为数据更新了
  router.push("/Profile");
}

const goBack = () => {
  router.back();
}




onMounted(() => {
  News_addDTO.value.authorId = userStoreObject.userInfo.id;
  CoverUploadHeaders.value.token = localStorage.getItem('wx_access-client')
})


onBeforeRouteLeave(async(to, from) => {
  if((News_addDTO.value.content != null && News_addDTO.value.content != '') || News_addDTO.value.title != null || News_addDTO.value.categoryId != null){
    const isLeave = window.confirm('文章未保存，确定离开吗？')
    if (!isLeave) {
      return false // 阻止离开
    }
    else{
      //清理函数执行完成后再跳转
      if(News_addDTO.value.content != null){
        await DeleteFile(News_addDTO.value.content)
      }
      return true
    }
  }
  
})

</script>


<style lang="scss" scoped>
@mixin CommonStyle-center {
  display: flex;
  justify-content: center;
  align-items: center;
}

.news-publish {
  //background-color: aqua;
  height: 100vh;
  min-height: 600px;
  min-width: 350px;
  display: flex;
  flex-direction: column;
}

.tip {
  @include CommonStyle-center;
  top: 0;
  background-color: #409eff;
  color: #fff;
  height: 60px;
  min-height: 60px;
  position: relative;
}

.backIcon {
  position: absolute;
  left: 10px;
}

.titleBox {
  @include CommonStyle-center;
  height: 40px;
  padding: 0 10px;
  margin-top: 10px;
  margin-bottom: 10px;
  //background-color: rgb(242.5, 208.5, 157.5);
}

.CategoriesAndCoverBox {
  display: flex;
  height: 30vw;
  min-height: 105px;
  margin-bottom: 10px;
  //background-color: rgb(248, 152.1, 152.1);
}

.Categories-box {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 15px;
  padding: 10px;
  //background-image: linear-gradient(to top, #fad0c4 0%, #ffd1ff 100%);
  @include CommonStyle-center;
}

.Cover-box {
  flex: 1;
  overflow: hidden;
  padding: 10px;
  //background-image: linear-gradient(120deg, #f6d365 0%, #fda085 100%);
  @include CommonStyle-center;
}

.avatar-uploader {
  @include CommonStyle-center;
  height: 100%;
  width: 100%;
  border: 1px dashed black;
  border-radius: 5px;
  overflow: hidden;
}

:deep(.el-upload-list--picture .el-upload-list__item) {
  margin-top: 0;
  margin-bottom: 0;
  padding: 0;
}

:deep(.el-upload-list) {
  margin-top: 0;
}


.editBox {
  // height: 80vw;
  flex: 1;
  margin-bottom: 10px;
  //background-image: linear-gradient(to right, #43e97b 0%, #38f9d7 100%);
}

.submit-btn {
  width: 90%;
  height: 2.5rem;
  margin: 0 auto;
  margin-bottom: 15px;
  font-size: 16px;
  font-weight: 500;
  letter-spacing: 2px;
}
</style>